#include "Game.h"
#include "GameOverState.h"
#include "Factory.h"
#include "Ball.h"
#include "StringUtil.h"
#include "RadDegConvert.h"
#include "PlayState.h"
#include "Catapult.h"
#include "GUIManager.h"
#include "ReportError.h"
#include "SoundManager.h"
#include "PowerSlider.h"
#include "WinState.h"
#include <GL/glut.h>

PlayState::PlayState() : m_level("LevelData/Level1.txt")
{
	m_custCursor.SetTexPath("Textures/CustomCursor.png");
	m_custCursor.SetDims(Vec2f(0.1, 0.1));

	m_remBallsDist = 20;
	
	


}
void PlayState::OnActivated()
{
	
	m_score = 0;
	m_targetScore = 0;
	m_remainingBalls = 0;
	//Peter bit


	LoadButton();
	LoadText();


	LoadLevel();
	mp_powerSlider = new PowerSlider;

	LoadImg();
	mp_cam = new Camera;
	
	m_targetTxt.SetString("Target: " + ToString(m_targetScore));

	TheEventPoller::Instance()->AddHandler(this);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	gluPerspective(45,1280/720,1,8000);

	
	Vec3f pos = mp_cam->GetPos();
	Vec3f dest = mp_cam->GetDest();
	
	gluLookAt( pos.X, pos.Y, pos.Z,  dest.X, dest.Y, dest.Z,  0,1,0);

	
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	//m_musicIDTracks.push_back(1);
	
	TheSoundManager::Instance()->MusicPlay(1, 1);
	//Peter bit end


	//THE IMAGES
	

	//THE SCORE TEXT
 	//TheTextureManager::Instance()->LoadTex("Olde English Font Sheet.png", false);
 	
 	m_scoreTxt.SetActivate(true);
 	m_targetTxt.SetActivate(true);
	m_remBallsTxt.SetActivate(true);

	m_HUDbkgroundTop.SetActivate(true);
	m_HUDbkgroundBottom.SetActivate(true);
	m_scoreImg.SetActivate(true);
	mp_powerSlider->SetActivate(true);

	//Due to the evolving system of the catapult bool states
	//We ran out of time to implement the onscreen clickable buttons in game.
	/*
	m_rotLeftButt.SetActivate(true);
	m_rotRightButt.SetActivate(true);
	m_fireButt.SetActivate(true);
	*/

	//THE CUSTOM CURSOR	
	m_custCursor.SetActivate(true);

	TheGame::Instance()->BTCollisionsOn();

	glShadeModel(GL_SMOOTH);

	// Create light components
	GLfloat ambientLight[] = { 0.8f, 0.8f, 0.8f, 1.f };
	GLfloat diffuseLight[] = { 0.3f, 0.3f, 0.3f, 1.f };
	GLfloat specularLight[] = { 1.f, 1.f, 1.f, 1.f };
	GLfloat position[] = { 0.f, 10, 0.f, 1.0f };

	glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
	glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
	glLightfv(GL_LIGHT0, GL_POSITION, position);

	
}


void PlayState::LoadText()
{
	m_scoreTxt.SetTexPath("Textures/Olde English Font Sheet.png");
 	m_scoreTxt.SetPos(Vec2f(-0.5f, 1.f));
 	m_scoreTxt.SetSize(18);
 	m_scoreTxt.SetString(ToString(m_score));

	
	m_targetTxt.SetTexPath("Textures/Olde English Font Sheet.png");
 	m_targetTxt.SetPos(Vec2f(-0.1f, 1.f));
 	m_targetTxt.SetSize(18);
	m_targetTxt.SetString("Target: " + ToString(m_targetScore));

	m_remBallsTxt.SetTexPath("Textures/Olde English Font Sheet.png");
 	m_remBallsTxt.SetPos(Vec2f(-0.5f, -0.8f));
 	m_remBallsTxt.SetSize(18);
	m_remBallsTxt.SetString("Balls: " + ToString(m_remainingBalls));
}


void PlayState::LoadImg()
{
	//THE HUD BACKGROUND TOP
	//TheTextureManager::Instance()->LoadTex("Textures/HUD Background.png", false);
	m_HUDbkgroundTop.SetTexPath("Textures/HUD Background.png");
	m_HUDbkgroundTop.SetPos(Vec2f(0.0f, 1.8f));
	m_HUDbkgroundTop.SetDims(Vec2f(2.0f, 0.2f));
	
	//THE HUD BACKGROUND BOTTOM
	m_HUDbkgroundBottom.SetTexPath("Textures/HUD Background.png");
	m_HUDbkgroundBottom.SetPos(Vec2f(0.0f, 0.0f));
	m_HUDbkgroundBottom.SetDims(Vec2f(2.0f, 0.2f));

	// THE SCORE IMAGE
	//TheTextureManager::Instance()->LoadTex("Textures/Score Img.png", false);
	m_scoreImg.SetTexPath("Textures/Score Img.png");
	m_scoreImg.SetPos(Vec2f(0.f, 1.8f));
	m_scoreImg.SetDims(Vec2f(0.4f, 0.2f));


	mp_powerSlider->SetTexPath("Textures/PowerSlider.png");
	mp_powerSlider->SetPointerTexPath("Textures/PowerPointer.png");
	mp_powerSlider->SetPos(Vec2f(1.4, 0.6));
	mp_powerSlider->SetDims(Vec2f(0.1, 1));
	mp_powerSlider->PointerPos();
	
}

void PlayState::LoadButton()
{

	//Due to the evolving system of the catapult bool states
	//We ran out of time to implement the onscreen clickable buttons in game.
	/*
	//THE ROTATE LEFT BUTTON
	
	m_rotLeftButt.SetTexPath("Textures/Left.png");
	m_rotLeftButt.SetPos(Vec2f(0.08f, 0.0f));
	m_rotLeftButt.SetDims(Vec2f(0.4f, 0.2f));

	//THE ROTATE RIGHT BUTTON
	m_rotRightButt.SetTexPath("Textures/Right.png");
	m_rotRightButt.SetPos(Vec2f(1.5f, 0.0f));
	m_rotRightButt.SetDims(Vec2f(0.4f, 0.2f));

	//THE FIRE BUTTON
	m_fireButt.SetTexPath("Textures/Fire.png");
	m_fireButt.SetPos(Vec2f(0.8f, 0.0f));
	m_fireButt.SetDims(Vec2f(0.4f, 0.2f));
	*/

}


void PlayState::OnDeactivated()
{
	m_HUDbkgroundTop.SetActivate(false);
	m_HUDbkgroundBottom.SetActivate(false);
	m_scoreImg.SetActivate(false);

	m_scoreTxt.SetActivate(false);
	m_remBallsTxt.SetActivate(true);
	m_targetTxt.SetActivate(false);

	//Due to the evolving system of the catapult bool states
	//We ran out of time to implement the onscreen clickable buttons in game.
	/*
	m_rotLeftButt.SetActivate(false);
	m_rotRightButt.SetActivate(false);
	m_fireButt.SetActivate(false);
	*/

	m_custCursor.SetActivate(false);
	mp_powerSlider->SetActivate(false);

	delete mp_cam;
	delete mp_powerSlider;

	mp_ball = nullptr;
	mp_catapult = nullptr;

	TheGame::Instance()->BTCollisionsOn(false);

	TheEventPoller::Instance()->RemoveHandler(this);
}

void PlayState::Draw()
{

	glClearColor(0, 0, 0, 1);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45,1280/720,1,10000);

	//glDisable(GL_LIGHTING);

	//Get camera info
	Vec3f pos = mp_cam->GetPos();
	Vec3f dest = mp_cam->GetDest();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	float xDiff = 0;
	float yDiff = 10.0f;
	float zDiff = 20.0f;

	gluLookAt(pos.X, pos.Y + yDiff , pos.Z + zDiff, dest.X, dest.Y, dest.Z, 0, 1, 0);

	TheGame::Instance()->DrawGameObjects();
	TheGUIManager::Instance()->Draw();


	//DrawRemainingBalls();

}

void PlayState::Update()
{
	
	TheGame::Instance()->UpdateGameObjects();
	m_scoreTxt.SetString(ToString(m_score));
	TheGUIManager::Instance()->Update();
	
	mp_cam->Update();

	if(m_remainingBalls < 0)
	{
		CheckWin();
	}

	if (m_rotLeftButt.GetPressed())
	{
		//rotate the catapult left
		m_rotLeftButt.SetTexPath("Textures/Left Pressed.png");
	}
	{
		m_rotLeftButt.SetTexPath("Textures/Left.png");
	}
	if (m_rotRightButt.GetPressed())
	{
		//rotate the catapult right
		m_rotRightButt.SetTexPath("Textures/Right Pressed.png");
	}
	else
	{
		m_rotRightButt.SetTexPath("Textures/Right.png");
	}
	if(m_fireButt.GetPressed())
	{
		//FIRE!!!
		m_fireButt.SetTexPath("Textures/Fire Pressed.png");
	}
	else
	{
		m_fireButt.SetTexPath("Textures/Fire.png");
	}


	m_remBallsTxt.SetString("Balls: " + ToString(m_remainingBalls));
}

void PlayState::SetTotalBalls(int balls)
{
	m_totalBalls = balls;
	m_remainingBalls = balls;
}
void PlayState::SetLevel(const std::string& fileName)
{
	m_level = fileName;
	
}

void PlayState::DrawRemainingBalls()
{
	/*

	//Couldn't implement in time
	//Designed to display the remaining balls to fire
	//and distribute them around the catapult.
	//Instead we used another GUI text object showing the number remaining.

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	
	if(m_remainingBalls > 1)
	{
		float angleBetween = 360/ (m_remainingBalls-1);

		for( unsigned int i = 0; i < m_remainingBalls; i++)
		{
			float angle = i * angleBetween;

			float x = m_remBallsDist * cos(DegToRad(angle));
			float z = m_remBallsDist * cos(DegToRad(angle));

			glPushMatrix();

			glTranslatef(x, 0, z);
			glutSolidSphere(8, 16, 16);

			glPopMatrix();

		}
	}	
	*/
}

void PlayState::OnMouseButtonDownEvent(const SDL_MouseButtonEvent& m)
{
	m_rotLeftButt.OnMouseButtonDownEvent(m);
	m_rotRightButt.OnMouseButtonDownEvent(m);
	m_fireButt.OnMouseButtonDownEvent(m);

	if(m.button == SDL_BUTTON_LEFT)
	{
		if(m.state == SDL_PRESSED)
		{
			if (m_rotLeftButt.GetPressed())
			{
				mp_catapult->TurnLeft();
			}
			else if (m_rotRightButt.GetPressed())
			{
				mp_catapult->TurnLeft();
			}
			else if (m_fireButt.GetPressed())
			{
				mp_catapult->Fire();
			}
		}
		else if(m.state == SDL_RELEASED)
		{

		}
	}
}

void PlayState::OnMouseMotionEvent(const SDL_MouseMotionEvent& mm)
{
	m_rotLeftButt.OnMouseMotionEvent(mm);
 	m_rotRightButt.OnMouseMotionEvent(mm);
 	m_fireButt.OnMouseMotionEvent(mm);
 	m_custCursor.OnMouseMotionEvent(mm);
}

void PlayState::OnKeyboardEvent(const SDL_KeyboardEvent& k)
{

	if(k.keysym.sym == SDLK_ESCAPE && k.state == SDL_PRESSED)
	{
		exit(0);
	}

}

int PlayState::GetScore()
{
	return m_score;
}

void PlayState::AddToScore(int score)
{
	m_score += score;
}

Ball* PlayState::GetBall()
{
	return mp_ball;
}

void PlayState::SetBall(Ball* b)
{
	assert(!mp_ball);
	mp_ball = b;
}

void PlayState::BallThrown()
{
	m_remainingBalls--;	
	mp_catapult->MakeAiming();
}

void PlayState::CheckWin()
{
	if(m_score >= m_targetScore)
	{
		//WIN
		TheGame::Instance()->SetGameState(TheWinState::Instance());

	}
	else
	{
		//Lose
		TheGame::Instance()->SetGameState(TheGameOverState::Instance());
	}
}

Catapult* PlayState::GetCatapultAddress()
{
	return mp_catapult;
}

void PlayState::SetCatapultAddress(Catapult* catapult)
{
	assert(!mp_catapult);
	mp_catapult = catapult;
}

void PlayState::SetTargetScore(int target)
{
	m_targetScore = target;
}

bool PlayState::LoadLevel()
{
	TheGame::Instance()->DeleteGameObjects();
	m_score = 0;
	File f;

	//Open the File
	if(!f.OpenRead(m_level))
	{
		ReportError("Cannot Open File!: " + __LINE__ + m_level);
		return false;
	}
	//Read from file
	while (true)
	{
		//read a line from the file
		std::string	str;
		if (!f.GetString(&str))
		{
			break;
		}
		else
		{
			//use factory to make object
			GameObject* g = TheGameObjectFactory::Instance()->Create(str);
			if (!g)
			{
				ReportError("I don't know how to create this kind of object " + __LINE__ );
				break;
			}

			//Load in object ID
			int id = 0;
			if(!f.GetInteger(&id))
			{
				ReportError("I Expected an ID at this point " + __LINE__ );
				break;
			}
			g->SetId(id);

			//make the object load itself
			if (!g->Load(&f))
			{
				ReportError("Failed to load object: " + str + ToString(id));
				return false;
			}
			TheGame::Instance()->AddGameObject(id,g);
			//add the object to the container of game objects
		}
	}
	return true;
}


